using System;
using System.Windows.Forms;
using System.ComponentModel;

namespace FilterControls
{
    public class FilterTextBox : TextBox
    {
        private string _forbidenChars;
        private bool _internalEditing;
        private bool _captleLetterOnly;
        private AcceptableCharacters _acceptableChar;

        public enum AcceptableCharacters
        {
            LetterOnly = 0,
            DigitOnly,
            LetterOrDigit,
            All
        }

        public FilterTextBox()
        {
            _forbidenChars = string.Empty;
            _internalEditing = false;
            _captleLetterOnly = false;
            _acceptableChar = AcceptableCharacters.All;
        }

        #region " Appearance "

        /// <summary>
        /// Indicate wich characters can't be in string
        /// </summary>
        [Category("Behavior"),DefaultValue(""),
            Description("Indicate wich characters can't be in string")]
        public string ForbidenChars
        {
            get
            {
                return _forbidenChars;
            }
            set
            {
                _forbidenChars = value;
                Text = Text;
            }
        }

        /// <summary>
        /// Indicate only Captle characters can write
        /// </summary>
        [Category("Behavior"), DefaultValue(false),
            Description("Indicate only Captle characters can write"), Browsable(true)]
        public bool CaptleLettersOnly
        {
            get
            {
                return _captleLetterOnly;
            }
            set
            {
                _captleLetterOnly = value;
                Text = Text;
            }
        }

        /// <summary>
        /// Indicate wich type of characters are acceptable
        /// </summary>
        [Category("Behavior"), DefaultValue(AcceptableCharacters.All),
            Description("Indicate wich type of characters are acceptable"), Browsable(true)]
        public AcceptableCharacters AcceptableChars
        {
            get
            {
                return _acceptableChar;
            }
            set
            {
                _acceptableChar = value;
                Text = Text;
            }
        }
        #endregion

        #region " Overrides "

        public override string Text
        {
            get
            {
                return base.Text;
            }
            set {
                base.Text = _internalEditing ? value : RemoveForbidens(value);
            }
        }

        protected override void OnTextChanged(EventArgs e)
        {
            base.OnTextChanged(e);
            int selS = SelectionStart;
            _internalEditing = true;
            Text = RemoveForbidens(Text, ref selS);
            _internalEditing = false;
            SelectionStart = selS;
        }
        #endregion

        private string RemoveForbidens(string st, ref int selStart)
        {
            if (_captleLetterOnly)
                st = st.ToUpper();

            for (int i = st.Length - 1; i >= 0; i--)
            {
                if (_forbidenChars.IndexOf(st[i]) != -1)
                {
                    st = st.Remove(i, 1);
                    if (i < selStart)
                        selStart--;
                }
                else if (_acceptableChar == AcceptableCharacters.DigitOnly && char.IsDigit(st[i]) != true)
                {
                    st = st.Remove(i, 1);
                    if (i < selStart)
                        selStart--;
                }
                else if (_acceptableChar == AcceptableCharacters.LetterOnly && char.IsLetter(st[i]) != true)
                {
                    st = st.Remove(i, 1);
                    if (i < selStart)
                        selStart--;
                }
                else if (_acceptableChar == AcceptableCharacters.LetterOrDigit && char.IsLetterOrDigit(st[i]) != true)
                {
                    st = st.Remove(i, 1);
                    if (i < selStart)
                        selStart--;
                }
            }
            return st;
        }

        private string RemoveForbidens(string st)
        {
            int i = st.Length;
            return RemoveForbidens(st, ref i);
        }
    }
}